#pragma once
#include <iostream>
#include <cstdint>
#include "online_user_manager.hpp"
#include "user_table.hpp"
#include "util.hpp"
#include <websocketpp/server.hpp>
#include <websocketpp/config/asio_no_tls.hpp>

using wsserver_t = websocketpp::server<websocketpp::config::asio>;

#define BOARD_ROW 15  // 棋盘行数
#define BOARD_COL 15  // 棋盘列数
#define CHESS_WHITE 1 // 白子
#define CHESS_BLACK 2 // 黑子

typedef enum
{
    GAME_START,
    GAME_OVER
} room_status;



// 房间类  实现棋局对战和实时聊天
class room
{
public:
    room(uint64_t room_id, user_table *tb_user, online_user_manager *online_user_manager)
        : _room_id(room_id),
          _room_status(GAME_START),
          _player_num(0),
          _tb_user(tb_user),
          _online_user_manager(online_user_manager),
          _board(BOARD_ROW, std::vector<int>(BOARD_COL, 0))
    {
        DBG_LOG("%lu init success!", _room_id);
    }
    ~room()
    {
        DBG_LOG("%lu destroy success%", _room_id);
    }

public:
    // 常规获取私有成员信息函数和添加下棋者信息
    uint64_t room_id() { return _room_id; }
    room_status get_room_status() { return _room_status; }
    int player_num() { return _player_num; }
    void add_white_id(uint64_t white_uid)
    {
        _white_id = white_uid;
        _player_num++;
    }
    void add_black_id(uint64_t black_uid)
    {
        _black_id = black_uid;
        _player_num++;
    }
    uint64_t get_white_id() { return _white_id; }
    uint64_t get_black_id() { return _black_id; }

    // 处理下棋动作
    Json::Value handle_chess(Json::Value &root)
    {
        // 构建响应
        Json::Value json_resp;
        json_resp["optype"] = "put_chess"; // 添加操作类型

        // 从Json中获取一些相应的信息
        int chess_row = root["row"].asInt();
        int chess_col = root["col"].asInt();
        uint64_t cur_uid = root["uid"].asUInt64();
        uint64_t another_uid = cur_uid == _white_id ? _black_id : _white_id;

        // 判断对方是否在线，不在线就算另一方获胜
        if (!_online_user_manager->in_room(another_uid))
        {
            json_resp["result"] = true;
            json_resp["reason"] = "恭喜你，对方已离开游戏，你赢了！";
            json_resp["winner"] = (Json::UInt64)cur_uid;
            json_resp["uid"] = (Json::UInt64)cur_uid; // 添加请求用户的ID
            return json_resp;
        }

        // 获取下棋坐标，判断是否合理（是否有空位置，是否没有超出边界）
        if (chess_row < 0 || chess_row >= BOARD_ROW || chess_col < 0 || chess_col >= BOARD_COL)
        {
            json_resp["result"] = false;
            json_resp["reason"] = "坐标超出边界！";
            return json_resp;
        }
        if (_board[chess_row][chess_col] != 0)
        {
            json_resp["result"] = false;
            json_resp["reason"] = "该位置已经有棋子了！";
            return json_resp;
        }

        // 这一步则为能够合法下棋，需要获取颜色
        int cur_color = cur_uid == _white_id ? CHESS_WHITE : CHESS_BLACK;
        _board[chess_row][chess_col] = cur_color;
        
        // 添加下棋的位置和颜色信息到响应中
        json_resp["row"] = chess_row;
        json_resp["col"] = chess_col;
        json_resp["color"] = cur_color;
        json_resp["uid"] = (Json::UInt64)cur_uid;

        // 判断是否获胜
        uint64_t winner_id = check_win(chess_row, chess_col, cur_color);
        if (winner_id != 0)
        {
            json_resp["reason"] = "五星连珠！";
            json_resp["winner"] = (Json::UInt64)winner_id;
        }
        else
        {
            // 如果winner中的数字为0，则表示没有获胜，而且是合法的下棋
            json_resp["winner"] = 0;
        }
        json_resp["result"] = true;
        return json_resp;
    }

    /// 处理聊天动作
    Json::Value handle_chat(Json::Value &root)
    {
        // 构建响应
        Json::Value json_resp;

        // 从Json中获取一些相应的信息,检测是否含有敏感词
        // 对于敏感词的处理后期TODO（敏感词模块）
        std::string message = root["reason"].asString();
        size_t pos = message.find("垃圾");
        if (pos != std::string::npos)
        {
            json_resp["result"] = false;
            json_resp["reason"] = "请勿发送敏感信息！";
            return json_resp;
        }

        json_resp["result"] = true;
        return json_resp;
    }

    // 处理退出房间动作
    // 此函数现在有问题？（TODO）
    void handle_exit(uint64_t uid)
    {
        // 如果是下棋中途退出，则判对方胜利，如果正常棋盘结束后退出，那是正常退出
        Json::Value json_resp;
        if (_room_status == GAME_START)
        {
            uint64_t winner_id = uid == _white_id ? _black_id : _white_id;
            uint64_t loser_id = uid == _white_id ? _white_id : _black_id;
            json_resp["result"] = true;
            json_resp["reason"] = "恭喜你，你赢了！";
            json_resp["optype"] = "put_chess";
            json_resp["room_id"] = (Json::UInt64)_room_id;
            json_resp["uid"] = (Json::UInt64)uid;
            json_resp["row"] = -1;
            json_resp["col"] = -1;
            json_resp["winner"] = (Json::UInt64)winner_id;
            _tb_user->win(winner_id);
            _tb_user->lose(loser_id);
            _room_status = GAME_OVER;
            broadcast(json_resp);
        }
        else
        {
            // 游戏结束，正常退出
            json_resp["result"] = true;
            json_resp["reason"] = "对方玩家已退出房间";
            json_resp["winner"] = (Json::UInt64)0; // 已经结束了，没有获胜者
            broadcast(json_resp);
        }
        //房间中的玩家数量--
        // 重置离开玩家的ID
        if (_white_id == uid) {
            _white_id = 0;
        } else if (_black_id == uid) {
            _black_id = 0;
        }
        _player_num--;
        return;
    }


    //根据请求的类型不同来调用不同的请求函数
    void handle_request(Json::Value &root){
        DBG_LOG("handle_request: %s", root.toStyledString().c_str());
        DBG_LOG("收到的房间ID: %lu", root["room_id"].asUInt64());
        // 2.校验房间号是否匹配
        Json::Value json_resp;
        uint64_t room_id = root["room_id"].asUInt64();
        if (room_id != _room_id){
            DBG_LOG("房间号不匹配");
            json_resp["optype"] = root["optype"].asString();
            json_resp["result"] = false;
            json_resp["reason"] = "房间号不匹配";
            return broadcast(json_resp); // 广播消息
        }

        // 3.根据不同的请求类型调用不同的处理函数
        if (root["optype"].asString() == "put_chess"){
            DBG_LOG("处理下棋请求");
            json_resp = handle_chess(root); // 处理下棋的请求，得到结果放到resp中
            // 检查resp中是否成功
            //2.1 判断是否有winner键
            if (json_resp["winner"].asUInt64() != 0) {
                    uint64_t winner_id = json_resp["winner"].asUInt64();
                    uint64_t loser_id = winner_id == _white_id ? _black_id : _white_id;
                    _tb_user->win(winner_id);
                    _tb_user->lose(loser_id);
                    _room_status= GAME_OVER;
             } 
            }else if (root["optype"].asString() == "chat") {
                json_resp = handle_chat(root);
            }else {
                json_resp["optype"] = root["optype"].asString();
                json_resp["result"] = false;
                json_resp["reason"] = "未知请求类型";
            }
            std::string body;
            json_util::serialize(json_resp, body);
            DBG_LOG("房间-广播动作: %s", body.c_str());
            return broadcast(json_resp);
    }
    // 广播消息
    //观战模式还未实现，这个只是广播给两个下棋的人，观战模式TODO
    void broadcast(Json::Value &json_resp)
    {
        // 1.对要响应的消息进行序列化
        std::string body;
        json_util::serialize(json_resp, body);
         DBG_LOG("房间 %lu 广播消息，白棋ID: %lu, 黑棋ID: %lu", _room_id, _white_id, _black_id);
        
          // 检查玩家是否在房间中
        bool white_in_room = _online_user_manager->in_room(_white_id);
        bool black_in_room = _online_user_manager->in_room(_black_id);
        DBG_LOG("白棋玩家在房间: %s, 黑棋玩家在房间: %s", 
                white_in_room ? "是" : "否", 
                black_in_room ? "是" : "否");
        
        // 如果是处理'房间号不匹配'的错误响应，只发送给请求的用户
        if (json_resp["result"].asBool() == false && json_resp["reason"].asString() == "房间号不匹配") {
            // 安全地获取请求用户的ID，如果不存在则默认发送给所有在线用户
            if (json_resp.isMember("uid")) {
                uint64_t req_uid = json_resp["uid"].asUInt64();
                wsserver_t::connection_ptr req_conn = nullptr;
                
                if (req_uid == _white_id) {
                    req_conn = _online_user_manager->get_conn_from_game_room(_white_id);
                } else if (req_uid == _black_id) {
                    req_conn = _online_user_manager->get_conn_from_game_room(_black_id);
                }
                
                if (req_conn.get() != nullptr) {
                    req_conn->send(body);
                    return;
                }
            }
            // 如果无法获取请求用户的连接，则继续进行正常广播
        }
        
        // 2.获取房间中所有用户的通信连接
        // 3.构建响应
        wsserver_t::connection_ptr wconn = _online_user_manager->get_conn_from_game_room(_white_id);
        if (wconn.get() != nullptr)
        {
            wconn->send(body);//服务器向白棋玩家广播
        }
        else
        {
            DBG_LOG("房间---白棋玩家连接获取失败");
        }
        wsserver_t::connection_ptr bconn = _online_user_manager->get_conn_from_game_room(_black_id);
        if (bconn.get() != nullptr)
        {
            bconn->send(body);//服务器向黑棋玩家广播
        }
        else
        {
            DBG_LOG("房间---黑棋玩家连接获取失败");
        }
    }

private:
    // 判断五子棋某个方向是否连线，row和col为当前坐标，row_off和col_off为偏移量
    bool five_in_a_row(int row, int col, int row_off, int col_off, int color)
    {
        int count = 1;
        int search_row = row + row_off; // 当前行坐标
        int search_col = col + col_off; // 当前列坐标
        while (search_row >= 0 && search_col >= 0 && search_row < BOARD_ROW && search_col < BOARD_COL && _board[search_row][search_col] == color)
        {
            count++; // 同色棋子+1
            // 更改坐标
            search_row += row_off;
            search_col += col_off;
        }
        search_row = row - row_off; // 当前行坐标
        search_col = col - col_off; // 当前列坐标
        while (search_row >= 0 && search_col >= 0 && search_row < BOARD_ROW && search_col < BOARD_COL && _board[search_row][search_col] == color)
        {
            count++; // 同色棋子+1
            // 更改坐标
            search_row -= row_off;
            search_col -= col_off;
        }
        return (count >= 5);
    }
    uint64_t check_win(int row, int col, int color)
    {
        if (five_in_a_row(row, col, 1, 0, color) || five_in_a_row(row, col, 0, 1, color) || five_in_a_row(row, col, 1, 1, color) || five_in_a_row(row, col, 1, -1, color))
        {
            // 判断胜利的颜色是哪个然后返回对应的玩家id出去
            return color == CHESS_WHITE ? _white_id : _black_id;
        }
        return 0;
    }

private:
    uint64_t _room_id;                         // 房间id
    room_status _room_status;                  // 房间状态
    int _player_num;                           // 房间人数
    uint64_t _white_id;                        // 白子id
    uint64_t _black_id;                        // 黑子id
    user_table *_tb_user;                      // 用户表
    online_user_manager *_online_user_manager; // 在线用户管理
    std::vector<std::vector<int>> _board;      // 棋盘
};